﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO;
using HsCommX;

namespace CodeGen
{
    public partial class frmMain : Form
    {
        HsGateway hs = new HsGateway();

        public frmMain()
        {
            InitializeComponent();

            if (hs.Connect("prmNetwork.txt"))
                MessageBox.Show("链接成功");
            else
            {
                MessageBox.Show("连接失败!");
            }
        }

        private void btnGo_Click(object sender, EventArgs e)
        {
            代码生成();

            MessageBox.Show((HsGateway.GetSendId(403)+"\r\n"+Int64.MaxValue.ToString()));
        }

        private void 代码生成()
        {
            List<MethodCode> methods = new List<MethodCode>();
            ErrorEnmuCode errors = new ErrorEnmuCode();


            using (FileStream fs = new FileStream("error.txt", FileMode.Open, FileAccess.Read))
            {
                using (StreamReader reader = new StreamReader(fs, Encoding.UTF8))
                {
                    string text = string.Empty;
                    StringBuilder sb = new StringBuilder();
                    while (!reader.EndOfStream)
                    {
                        text = reader.ReadLine().Trim();

                        if (text == string.Empty)
                            continue;
                        var ts  =text.Split(':');
                        errors.Add(int.Parse(ts[0]), new ErrorCode() { code = int.Parse(ts[0]), name = ts[1] });
                    }
                }
            }


            using (FileStream fs = new FileStream("Input.txt", FileMode.Open, FileAccess.Read))
            {
                using (StreamReader reader = new StreamReader(fs, Encoding.UTF8))
                {
                    string text = string.Empty;
                    StringBuilder sb = new StringBuilder();
                    while (!reader.EndOfStream)
                    {
                        text = reader.ReadLine().Trim();

                        if (text == string.Empty)
                            continue;

                        if (text.StartsWith("功能号"))
                        {
                            string mcode = sb.ToString();
                            if (mcode != string.Empty)
                            {
                                methods.Add(new MethodCode(mcode));
                                sb = new StringBuilder();
                            }
                        }

                        if (text.StartsWith("-"))
                        {
                            var code = new ErrorCode(text);
                            if (!errors.ContainsKey(code.code))
                            {
                                errors.Add(code.code,code);
                            }
                            else if ((!string.IsNullOrEmpty(code.comment)) && code.comment != errors[code.code].comment)
                            {
                                errors[code.code].comment += "\r\n ///" + code.comment;
                            }
                        }

                        sb.AppendLine(text);
                    }
                    methods.Add(new MethodCode(sb.ToString()));

                    sb = new StringBuilder();
                    sb.AppendLine(errors.Render());
                    methods.ForEach(m => sb.AppendLine(m.Render()));
                    
                    this.textBox1.Text = sb.ToString();
                }
            }
        }

        private void btnTest_Click(object sender, EventArgs e)
        {
            
            StringBuilder sb = new StringBuilder();

            try
            {
                var result = hs.F200客户登录校验(210053, 2100, "1", "383180", "0", "210027623");
                sb.AppendLine("客户基本信息：" + result.client_name);                
                sb.AppendLine("资金账号：" + result.fund_account);
                sb.AppendLine("开通的币种个数：" + result.money_count);
                sb.AppendLine("币种类别：" + result.money_type); //0 人民币; 1 美元; 2 港币
                sb.AppendLine("当前余额：" + result.current_balance);
                sb.AppendLine("可用金额：" + result.enable_balance);

                var result2 = hs.F405查询资金(210053, 2100, result.fund_account, "383180", "0");
                sb.AppendLine("可取现金：" + result2[0].fetch_cash);
                sb.AppendLine("资产总值：" + result2[0].asset_balance);

                var result3 = hs.F407查询股东(210053, 2100, result.fund_account, "383180", "", "", "", 5, "");
                sb.AppendLine("上海股东账号：" + result3[0].stock_account);
                sb.AppendLine("深圳股东账号：" + result3[1].stock_account);
                sb.AppendLine("----------------------------------------\r\n");

                sb.AppendLine("证券持仓信息和卖出信息配置");
                for (int i = 0; i < result3.Count; i++)
                {
                    var result4 = hs.F403查询股票(210053, 2100, result.fund_account, "383180", "", result3[i].stock_account, "", "", "0", 50, "");
                    for (int j = 0; j < result4.Count; j++)
                    {
                        sb.AppendLine("证券代码：" + result4[j].stock_code + "证券名称：" + result4[j].stock_name + " 当前数量：" + result4[j].current_amount + " 可卖数量：" + result4[j].enable_amount);
                    }
                }                
                sb.AppendLine("\r\n----------------------------------------\r\n");

                sb.AppendLine("根据证券代码查询证券名称：F105");
                var result5 = hs.F105查询股票市场(2100, "600387");
                sb.AppendLine(result5[0].stock_code + ", " + result5[0].stock_name);


            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
            this.textBox1.Text = sb.ToString();
        }

        private void btnTest2_Click(object sender, EventArgs e)
        {
            StringBuilder sb = new StringBuilder();

            try
            {
                #region 200 客户登陆校验
                var result = hs.F200客户登录校验(210053, 2100, "1", "383180", "0", "210027623");
                sb.AppendLine("F200客户登录校验: 客户基本信息：" + result.client_name);
                sb.AppendLine("资金账号：" + result.fund_account);
                sb.AppendLine("开通的币种个数：" + result.money_count);
                sb.AppendLine("币种类别：" + result.money_type); //0 人民币; 1 美元; 2 港币
                sb.AppendLine("当前余额：" + result.current_balance);
                sb.AppendLine("可用金额：" + result.enable_balance + result.init_date);
                #endregion

                #region 405&407 客户信息查询（资金&股东账号）
                var result2 = hs.F405查询资金(210053, 2100, result.fund_account, "383180", "0");
                sb.AppendLine("F405查询资金: 可取现金：" + result2[0].fetch_cash);
                sb.AppendLine("资产总值：" + result2[0].asset_balance);

                var result3 = hs.F407查询股东(210053, 2100, result.fund_account, "383180", "", "", "", 5, "");
                sb.AppendLine("F407查询股东: 上海股东账号：" + result3[0].stock_account);
                sb.AppendLine("深圳股东账号：" + result3[1].stock_account);
                sb.AppendLine("----------------------------------------\r\n");
                #endregion

                #region 105 根据证券代码通过恒生接口查询股票信息（弃用）
                //sb.AppendLine("根据证券代码查询证券名称：F105");
                //var result5 = hs.F105查询股票市场(2100, "600387");
                //sb.AppendLine(result5[0].stock_code + ", " + result5[0].stock_name);

                //sb.AppendLine("\r\n----------------------------------------\r\n");
                #endregion

                #region 403 查询持仓 股票信息
                //sb.AppendLine("证券持仓信息和卖出信息配置");
                //for (int i = 0; i < result3.Count; i++)
                //{
                //    var result4 = hs.F403查询股票(210053, 2100, result.fund_account, "383180", "", result3[i].stock_account, "", "", "0", 50, "");
                //    for (int j = 0; j < result4.Count; j++)
                //    {
                //        sb.AppendLine("证券代码：" + result4[j].stock_code + "证券名称：" + result4[j].stock_name + " 当前数量：" + result4[j].current_amount + " 可卖数量：" + result4[j].enable_amount + " 交易类别：" + result4[j].exchange_type);
                //    }
                //}
                //sb.AppendLine("\r\n----------------------------------------\r\n");

                #endregion

                #region 402&411 查询当日成交 & 查询历史成交 （308也可查出历史成交记录）
                //查询成交和查询历史成交
                //var result8 = hs.F402查询成交(210053, 2100, result.fund_account, "383180", "", "", "", "", "0", 50, "");

                //for (int i = 0; i < result8.Count; i++)
                //{
                //    sb.AppendLine("成交日期：" + result8[i].date + " 成交时间：" + result8[i].business_time + " 证券账号：" + result8[i].stock_account + " 交易类别：" + result8[i].exchange_type + " 成交类别名称：" + result8[i].type_name + " 证券名称：" + result8[i].stock_name + " 成交数量：" + result8[i].business_amount + " 成交价格：" + result8[i].business_price + " 买卖方向：" + result8[i].entrust_bs + " 成交金额：" + result8[i].business_balance + "\r\n");
                //}

                var result9 = hs.F411查询历史成交(210053, 2100, result.fund_account, "383180", 20110901, 20110908, "", "", "", "", 50, "");
                sb.AppendLine("F411查询历史成交: ");
                for (int i = 0; i < result9.Count; i++)
                {
                    sb.AppendLine("委托号："+result9[i].entrust_no+" 流水号："+result9[i].serial_no+" 申报号："+result9[i].report_no + " 成交日期：" + result9[i].date + " 成交时间：" + result9[i].business_time + " 证券账号：" + result9[i].stock_account + " 交易类别：" + result9[i].exchange_type + " 交易名称：" + result9[i].exchange_name + " 证券名称：" + result9[i].stock_name + " 成交数量：" + result9[i].occur_amount + " 成交价格：" + result9[i].business_price + " 买卖方向：" + result9[i].entrust_bs + " 成交金额：" + result9[i].business_balance + "\r\n");
                }

                //sb.AppendLine("----------------------------------------\r\n");

                //308普通交割的查询结果 == 历史成交记录
                //var result13 = hs.F308普通交割(210053, 2100, result.fund_account, "383180", 20110901, 20110908, "", "", "", "1", "", 50, "");

                //for (int i = 0; i < result13.Count; i++)
                //{
                //    sb.AppendLine(result13[i].stock_code + " " + result13[i].stock_name + " " + result13[i].entrust_no + " " + result13[i].date + " " + result13[i].business_time);
                //}
                //sb.AppendLine("----------------------------------------\r\n");
                #endregion

                #region 451 查询当日委托

                #region 401 每次根据当日委托号来查询当日委托（只能单条查询 有缺陷）
                //var result6 = hs.F401查询委托(210053, 2100, result.fund_account, "383180", "", "", "", "", "1", "", "0", 1, "", 0);//可查询当日委托 当locate_entrust_no为空，可查询最早一条委托                
                //sb.AppendLine("委托号：" + result6[0].entrust_no + " 股票代码：" + result6[0].stock_code + " 股票名称：" + result6[0].stock_name + " 申报时间：" + result6[0].report_time + " 买卖方向：" + result6[0].entrust_bs + " 成交数量：" + result6[0].business_amount + " 成交价格：" + result6[0].business_price + " 委托状态：" + result6[0].entrust_status + " 定位串：" + result6[0].position_str);

                #endregion

                //451 可以查询当日所有的委托记录
                //var result14 = hs.F451查询委托号码(210053, 2100, result.fund_account, "383180", "", "", 0, "");
                //for (int i = 0; i < result14.Count; i++)
                //{
                //    sb.AppendLine("委托号：" + result14[i].entrust_no + " 股票代码：" + result14[i].stock_code + " 股票名称：" + result14[i].stock_name + " 申报时间：" + result14[i].report_time + " 买卖方向：" + result14[i].entrust_bs + " 成交数量：" + result14[i].business_amount + " 成交价格：" + result14[i].business_price + " 委托状态：" + result14[i].entrust_status);
                //}

                //sb.AppendLine("\r\n--------------可撤单查询--------------------\r\n");
                ////无委托时不可用次查询，会报 -54 此委托不能撤单的 error
                //var result12 = hs.F303可撤单查询(210053, 2100, "383180", result.fund_account, "", 0, 50, "");

                //for (int i = 0; i < result12.Count; i++)
                //{
                //    sb.AppendLine("证券代码：" + result12[i].stock_code + " 证券名称：" + result12[i].stock_name + " 委托编号：" + result12[i].entrust_no + " 委托状态：" + result12[i].entrust_status + " 买卖方向：" + result12[i].entrust_bs);
                //}

                //sb.AppendLine("\r\n----------------------------------------\r\n");

                #endregion

                #region 委托买卖
                 //var result10 = hs.F300委托股票(210053, "383180", 2100, result.fund_account, "", result3[1].stock_account, "300093", "0");

                //var result11 = hs.F302委托确认(210053, "383180", 2100, result.fund_account, "2", result3[1].stock_account, "000793", 100, 6.10, "0", "1", "0", "");

                //sb.AppendLine("委托编号：" + result11.entrust_no.ToString()); 

                //sb.AppendLine("\r\n----------------------------------------\r\n");
                #endregion

                #region 委托撤单

                sb.AppendLine("\r\n--------------可撤单查询--------------------\r\n");
                //无委托时不可用次查询，会报 -54 此委托不能撤单的 error
                //var result12 = hs.F303可撤单查询(210053, 2100, "383180", result.fund_account, "", 0, 50, "");

                //for (int i = 0; i < result12.Count; i++)
                //{
                //    sb.AppendLine("证券代码：" + result12[i].stock_code + " 证券名称：" + result12[i].stock_name + " 委托编号：" + result12[i].entrust_no + " 委托状态：" + result12[i].entrust_status + " 买卖方向：" + result12[i].entrust_bs);
                //}

                //var result16 = hs.F304委托撤单(210053, 2100, result.fund_account, "383180", "0", "", 3526);
                //sb.AppendLine("委托编号：" + result16.entrust_no);
                sb.AppendLine("\r\n----------------------------------------\r\n");

                #endregion

                #region 查询行情
                var result17 = hs.F400查询行情("1", "600552");
                sb.AppendLine("F400查询行情: 证券代码600552" + "证券名称" + result17[0].stock_name + "最新价" + result17[0].last_price + "开盘价" + result17[0].open_price + "收盘价" + result17[0].close_price + "最高价" + result17[0].high_price + "最低价" + result17[0].low_price + "成交金额" + result17[0].business_balance + "成交数量" + result17[0].business_amount + "申买价一" + result17[0].buy_price1 + "申买量一" + result17[0].buy_amount1 + "申卖价一" + result17[0].sale_amount1 + "申卖量一" + result17[0].sale_amount1);
                #endregion

                #region 资金变动流水
                //var result7 = hs.F416查询历史资金证券流水详细信息(210053, 2100, result.fund_account, "383180", 20110801, 20110909, "0", "", 50, "");
                //for (int i = 0; i < result7.Count; i++)
                //{
                //    sb.AppendLine("发生日期：" + result7[i].date + " 发生时间：" + result7[i].report_time + " 交易类别：" + result7[i].exchange_type + " 发生金额：" + result7[i].occur_balance + " 本次余额：" + result7[i].post_balance + " 备注1：" + result7[i].remark + " 备注2：" + result7[i].remark2);
                //}

                #endregion         

                #region 委托股票
                var result18 = hs.F300委托股票(210053, "383180", 2100, result.fund_account, "", "", "000031", "0");
                
                #endregion

                sb.AppendLine("\r\n----------------------------------------\r\n");
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
            this.textBox1.Text = sb.ToString();
        }

        private void frmMain_FormClosing(object sender, FormClosingEventArgs e)
        {
            hs.DisConnect();
        }

    }

    #region 代码生成器

    public class MethodCode
    {
        static string[] spNR = { "\r\n" };
        static string[] spT = { "\t" };

        public string comment;
        public List<ParamCode> parameters;
        public ResultClassCode result;
        public string[] lines;

        public string num;
        public string name;
        public string returnSet;

        public MethodCode(string text)
        {
            lines = text.Split(spNR, StringSplitOptions.RemoveEmptyEntries);

            this.num = lines[0].Split(spT, StringSplitOptions.RemoveEmptyEntries)[1];
            this.name = lines[1].Split(spT, StringSplitOptions.RemoveEmptyEntries)[1];
            this.returnSet = lines[1].Split(spT, StringSplitOptions.RemoveEmptyEntries)[3];
            comment = "///" + lines[0] + spNR[0] + "///" + lines[1] + spNR[0] + "///" + lines[2] + spNR[0] + "///" + lines[3];

            //param
            int outidx = 0;
            this.parameters = new List<ParamCode>();
            for (int i = 5; i < lines.Length; i++)
            {
                if (!lines[i].StartsWith("输出参数"))
                {
                    var param = new ParamCode(lines[i]);
                    if (param.name == "identity_type" || param.name == "function_id")
                        continue;
                    parameters.Add(param);
                }
                else
                {
                    outidx = i;
                    break;
                }
            }

            //out
            List<string> resultCls=new List<string>();
            for (int i = outidx + 1; i < lines.Length; i++)
            {
                if (!lines[i].StartsWith("业务说明"))
                {
                    resultCls.Add(lines[i]);
                }
                else
                {
                    result = new ResultClassCode(this.name, "F" + this.num, resultCls.ToArray());
                    outidx = i;
                    break;
                }
            }

            //last
            for (int i = outidx ; i < lines.Length; i++)
            {
                comment += spNR[0] + "///" + lines[i];
            }
        }

        public string Render()
        {
            StringBuilder sb = new StringBuilder();

            sb.AppendLine(this.result.Render());

            sb.AppendLine("///<summary>");
            sb.AppendLine(this.comment);
            sb.AppendLine("///</summary>");
            foreach (var item in this.parameters)
            {
                if (ParamCode.skipParam.Contains(item.name))
                {
                    continue;
                }

                sb.AppendLine(string.Format("///<param name=\"{0}\">{1}</param>", item.name, item.comment));
            }

            sb.AppendFormat("public {0} F{2}{1}(", this.returnSet == "N" ? ("ResultF" + this.num) : ("List<ResultF" + this.num + ">"), this.name, this.num);
            for (int i = 0; i < this.parameters.Count; i++)
            {
                var item = this.parameters[i];
                if (ParamCode.skipParam.Contains(item.name))
                {
                    continue;
                }

                sb.AppendFormat("{0} {1}", item.TypeName, item.name);
                if (i < this.parameters.Count - 1)
                {
                    sb.Append(",");
                }
            }
            sb.Append(")");

            sb.AppendLine("{");
            sb.AppendLine(this.RenderBody());
            sb.AppendLine("}");
            return sb.ToString();
        }

        private string RenderBody()
        {
            StringBuilder sb = new StringBuilder();
            sb.AppendLine("if (this.objNet == null)");
            sb.AppendLine("throw new WebException(\"网络已断开，请重新连接\");");
            sb.AppendLine(string.Format("objComm.SetHead(branch_no, {0});",this.num));
            sb.AppendLine(string.Format("objComm.SetRange({0}, 1);",this.parameters.Count));
            foreach (var item in this.parameters)
            {
                sb.AppendLine(string.Format("objComm.AddField(\"{0}\");", item.name));
            }
            foreach (var item in this.parameters)
            {
                sb.AppendLine(string.Format("objComm.AddValue({0});", item.TypeName == "string" ? item.name : item.name + ".ToString()"));
            }

            sb.AppendLine("if (objComm.Send() != 0)");
            sb.AppendLine("    throw new WebException(\"指令发送失败\");");
            sb.AppendLine("objComm.FreePack();");
            sb.AppendLine("if (objComm.Receive() != 0)");
            sb.AppendLine("    throw new WebException(\"指令接收失败\");");
            sb.AppendLine("if (objComm.ErrorNo != 0 )");
            sb.AppendLine("    throw new HsCommException(objComm.ErrorMsg, objComm.ErrorNo);");

            if (returnSet == "N")
            {
                sb.AppendLine(string.Format("ResultF{0} result = null;", this.num));
                sb.AppendLine("if (objComm.Eof == 0)");
                sb.AppendLine("{");
                sb.AppendLine(string.Format("result = new ResultF{0}(objComm);", this.num)); 
                sb.AppendLine("}");
            }
            else
            {
                sb.AppendLine(string.Format("List<ResultF{0}> result = new List<ResultF{0}>();", this.num));
                sb.AppendLine("while (objComm.Eof == 0)");
                sb.AppendLine("{");
                sb.AppendLine(string.Format("result.Add(new ResultF{0}(objComm));", this.num));
                sb.AppendLine("objComm.MoveBy(1);");
                sb.AppendLine("}");
            }

            sb.AppendLine("return result;");
            return sb.ToString();
        }
    }

    public class ParamCode
    {
        public static string[] skipParam = { "version", "op_entrust_way", "identity_type", "op_station", "function_id" };

        static string[] spT = { "\t" };

        public string comment;
        public string type;
        public string name;
        public string TypeName
        {
            get
            {
                if (type.StartsWith("C"))
                {
                    return "string";
                }
                else if (type.Contains('.'))
                {
                    return "double";
                }
                else
                {
                    return "int";
                }
            }
        }

        public ParamCode(string text)
        {
            var ts = text.Split(spT, StringSplitOptions.RemoveEmptyEntries);
            this.name = ts[0];
            this.type = ts[1];
            this.comment = ts[2];
        }
    }

    public class ResultClassCode
    {
        public static string[] skipProp = { "error_no", "error_info" };

        List<ProperityCode> properites;
        string methodName;
        string methodNum;

        public ResultClassCode(string methodName, string methodNum, string[] lines)
        {
            this.methodName = methodName;
            this.methodNum = methodNum;
            this.properites = new List<ProperityCode>();
            foreach (string line in lines)
            {
                var prop = new ProperityCode(line);
                if (skipProp.Contains(prop.name))
                    continue;
                this.properites.Add(prop);
            }
        }

        public string Render()
        {
            StringBuilder sb = new StringBuilder();
            sb.AppendLine("/// <summary>");
            sb.AppendLine(string.Format("/// {0} {1} 的返回结果", this.methodNum , this.methodName));
            sb.AppendLine("/// </summary>");
            sb.AppendLine(string.Format("public class Result{0}", this.methodNum));
            sb.AppendLine("{");

            sb.AppendLine(string.Format("public Result{0}(Comm objComm)", this.methodNum));
            sb.AppendLine("{");
            foreach (var item in this.properites)
            {
                if (item.TypeName == "string")
                {
                    sb.AppendLine(string.Format("{0} = objComm.FieldByName(\"{0}\");", item.name));
                }
                if (item.TypeName == "double")
                {
                    sb.AppendLine(string.Format("{0} = Convert.ToDouble(objComm.FieldByName(\"{0}\"));", item.name));
                }
                if (item.TypeName == "int")
                {
                    sb.AppendLine(string.Format("{0} = Convert.ToInt32(objComm.FieldByName(\"{0}\"));", item.name));
                }
            }
            sb.AppendLine("}");

            foreach (var item in this.properites)
            {
                sb.AppendLine("/// <summary>");
                sb.AppendLine(string.Format("/// {0} ", item.comment));
                sb.AppendLine("/// </summary>");
                sb.AppendLine(string.Format("public {1} {0} ", item.name, item.TypeName) + "{ get; set; }");
            }

            sb.AppendLine("}");

            return sb.ToString();
        }
    }

    public class ProperityCode
    {
        static string[] spT = { "\t" };

        public string comment;
        public string type;
        public string name;

        public string TypeName
        {
            get {
                if (type.StartsWith("C"))
                {
                    return "string";
                }
                else if (type.Contains('.'))
                {
                    return "double";
                }
                else
                {
                    return "int";
                }
            }
        }

        public ProperityCode(string text)
        {
            var ts = text.Split(spT, StringSplitOptions.RemoveEmptyEntries);
            this.name = ts[0];
            this.type = ts[1];
            this.comment = ts[2];
        }
    }

    public class ErrorCode
    {
        static string[] spT = { "\t" };

        public int code;
        public string name;
        public string comment;

        public ErrorCode() { }
        public ErrorCode(string text)
        {
            var ts = text.Split(spT, StringSplitOptions.RemoveEmptyEntries);
            this.code = Convert.ToInt32(ts[0]);
            this.name = ts[1];
            if (ts.Length > 2)
            {
                this.comment = ts[2];
            }
        }
    }

    public class ErrorEnmuCode : Dictionary<int, ErrorCode>
    {
        public string Render()
        {
            StringBuilder sb = new StringBuilder();

            sb.AppendLine("public enum HsErrorCode : int");
            sb.AppendLine("{");

            foreach (ErrorCode code in this.Values.OrderBy(e => e.code))
            {
                if (code.comment != string.Empty)
                {
                    sb.AppendLine("/// <summary>");
                    sb.AppendLine(string.Format("/// {0}", code.comment));
                    sb.AppendLine("/// </summary>");
                }
                sb.AppendLine(string.Format("{0}={1},", code.name, code.code));
            }

            sb.AppendLine("}");

            return sb.ToString();
        }
    }
    
    #endregion
}
